
local alien = require 'alien'
local setmetatable, ipairs
    = setmetatable, ipairs
local tinsert
    = table.insert
local wincommon = require 'bindings.win32'


module (...)


COINIT_APARTMENTTHREADED = 2

CoInitialize = alien.ole32.CoInitialize
CoInitialize:types{ abi="stdcall"; ret="long" --[[HRESULT]]; "pointer" --[[must be null]] }

CoInitializeEx = alien.ole32.CoInitializeEx
CoInitializeEx:types{ abi="stdcall"; ret="long" --[[HRESULT]]; "pointer" --[[must be null]], "int" }

CoUninitialize = alien.ole32.CoUninitialize
CoUninitialize:types{ abi="stdcall"; ret="void" }

CoCreateInstance = alien.ole32.CoCreateInstance
CoCreateInstance:types{ abi="stdcall"; ret="long" --[[HRESULT]];
  "pointer" --[[REFCLSID]], "pointer" --[[LPUNKNOWN pUnkOuter]], "ulong" --[[DWORD dwClsContext]], "pointer" --[[REFIID]], "pointer" --[[LPVOID**]]
}

local comobj_proto = {}
local comobj_meta = {__index = comobj_proto}

IUnknown = setmetatable({
  IID = "00000000-0000-0000-C000-000000000046";
  name = "IUnknown";
  target = _M;
  {name="QueryInterface"; ret="long"; "pointer" --[[This]], "pointer" --[[REFIID]], "pointer" --[[void** ppvObj]]};
  {name="AddRef"; ret="ulong"; "pointer" --[[This]]};
  {name="Release"; ret="ulong"; "pointer" --[[This]]};
}, comobj_meta)

wincommon.definterface(IUnknown)

function comobj_proto:extend(def)
  for i,v in ipairs(def) do
    tinsert(v, 1, "pointer") -- This
    v.ret = v.ret or "ulong" -- HRESULT
  end
  for i = #self,1,-1 do
    tinsert(def, 1, self[i])
  end
  wincommon.definterface(def)
  return setmetatable(def, comobj_meta)
end

IDispatch = IUnknown:extend{
  IID = "00020400-0000-0000-C000-000000000046";
  name = "IDispatch";
  target = _M;
  {name = "GetTypeInfoCount"; ret="ulong"; "pointer" --[[unsigned int FAR* pctinfo]]};
  {name = "GetTypeInfo"; "uint" --[[iTInfo]], "ulong" --[[LCID]], "pointer" --[[ITypeInfo FAR* FAR* ppTInfo]]};
  {name = "GetIDsOfNames"; ret="ulong"; "pointer" --[[REFIID]], "pointer"--[[OLECHAR FAR* FAR* rgszNames]], "uint" --[[cNames]],
    "ulong" --[[LCID]], "pointer" --[[DISPID FAR* rgDispId]]};
  {name="Invoke"; ret="ulong"; "long" --[[DISPID dispIdMember]], "pointer" --[[REFIID riid]], "ulong" --[[LCID lcid]],
    "ushort" --[[WORD wFlags]], "pointer" --[[DISPPARAMS FAR* pDispParams]], "pointer" --[[VARIANT FAR* pVarResult]], 
    "pointer" --[[EXCEPINFO FAR* pExcepInfo]], "pointer" --[[unsigned int FAR* puArgErr]]};
}

CLSCTX_INPROC_SERVER = 0x1
CLSCTX_INPROC_HANDLER = 0x2
CLSCTX_INPROC = CLSCTX_INPROC_SERVER + CLSCTX_INPROC_HANDLER

IPersist = IUnknown:extend{
  IID = "0000010c-0000-0000-C000-000000000046";
  name = "IPersist";
  target = _M;
  {name="GetClassID"; "pointer" --[[CLSID *pClassID]]};
}
